#ifndef MQSERVER_MQ_ROUTE_HPP_
#define MQSERVER_MQ_ROUTE_HPP_
#include "../mqcomm/proto/mq_msg.pb.h"
#include "../mqcomm/mq_helper.hpp"
#include "../mqcomm/mq_logger.hpp"
#include <string>
#include <vector>

namespace mqserver 
{

class Router
{
public:
    static bool isLegalRoutingKey(const std::string& routing_key)
    {
        // 合法字符: a~z A~Z 0~9 . _
        for(char ch : routing_key) {
            if(!isValidCharacter(ch)) return false;
        }
        return true;
    }
    static bool isLegalBingdingKey(const std::string& bingding_key)
    {
        // 1. 合法字符: a~z A~Z 0~9 . _ * #
        for(char ch : bingding_key) {
            if(!isValidCharacter(ch) && ch != '*' && ch != '#') 
                return false;
        }   
        // 2. *和#必须独立存在(error_demo: news*.music#.*#)
        const std::string sep = ".";
        std::vector<std::string> words;
        helper::StringHelper::split(bingding_key, sep, &words);
        for(auto& word : words) 
        {
            if(word.size() > 1 && findIndependentChar(word))
                return false;
        }
        // 3. #* *# ##不能连续出现
        for (int i = 1; i < words.size(); ++i) 
        {
            if(words[i] == "#" && words[i - 1] == "*") return false;
            if(words[i] == "#" && words[i - 1] == "#") return false; 
            if(words[i] == "*" && words[i - 1] == "#") return false;
        }
        return true;
    }
    static bool route(proto::message::ExchangeType type, const std::string& routing_key, const std::string& bingding_key)
    {
        if(type == proto::message::ExchangeType::FANOUT) return true;
        if(type == proto::message::ExchangeType::DIRECT) return routing_key == bingding_key;
        // 主题匹配
        std::vector<std::string> rkeys, bkeys;
        const std::string sep = ".";
        helper::StringHelper::split(routing_key, sep, &rkeys);
        helper::StringHelper::split(bingding_key, sep, &bkeys);
        return TopicMatching(rkeys, bkeys);
    }
private:
    static bool findIndependentChar(const std::string word)
    {
        for(char ch : word) {
            if(ch == '*' || ch == '#') return true;
        }
        return false;
    }
    static bool TopicMatching(const std::vector<std::string>& rkeys, const std::vector<std::string>& bkeys)
    {
        int rsize = rkeys.size(), bsize = bkeys.size();
        std::vector<std::vector<bool>> dp(rsize + 1, std::vector<bool>(bsize + 1, 0));
        dp[0][0] = true;
        if(bkeys[0] == "#") dp[0][1] = true;
        for(int i = 1; i <= rsize; ++i)
        {
            for(int j = 1; j <= bsize; ++j) 
            {
                // b[j] == "#"
                if(bkeys[j - 1] == "#") dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
                // b[j] == r[i] || b[j] == '*'
                else dp[i][j] = (bkeys[j - 1] == "*" || rkeys[i - 1] == bkeys[j - 1]) && dp[i - 1][j - 1];
            }
        }
        return dp[rsize][bsize];
    }
    static bool isValidCharacter(char ch)
    {
        return (ch >= 'A' && ch <= 'Z') 
            || (ch >= 'a' && ch <= 'z') 
            || (ch >= '0' && ch <= '9') 
            || (ch == '_' || ch == '.');
    }
};

}
#endif